//
// Created by Lenovo on 2023/3/11.
//
#include "../../lib/googletest/include/gtest/gtest.h"

#include "../../src/include/API.h"
#include "../../src/include/ErrorCode.h"
#include <cstring>

bool chainIsValid(int len, char **result, char head, char tail, char reject) {
    if (len == 0) {
        return true;
    }
    //验证head
    if (head != 0) {
        if (result[0][0] != head) {
            return false;
        }
    }
    //验证tail
    if (tail != 0) {
        char *s = result[len - 1];
        char last_char = s[strlen(s) - 1];
        if (last_char != tail) {
            return false;
        }
    }
    //验证reject
    for (int i = 0; i < len; i++) {
        if (reject != 0 && result[i][0] == reject) {
            return false;
        }
    }
    //验证首尾相接
    for (int i = 1; i <= len - 1; i++) {
        char *pre = result[i - 1];
        char *next = result[i];
        char last_char = pre[strlen(pre) - 1];
        char first_char = next[0];
        if (last_char != first_char) {
            return false;
        }
    }
    return true;
}

void ccout(char* result[],int len){
    for(int i = 0;i<len;i++){
        cout << result[i] <<endl;
    }
}

//
bool coreErrorDectect(char* result[],int len,int expectedError){
    char error[5];
    sprintf(error, "%d", expectedError);
    if(len == 0){
        char* find= strstr(result[0], error);
        if(find != nullptr){
            return true;
        }
        return false;
    }
    return false;
}

//无环的简单测试 针对gen_chains_all
TEST(core,1) {
    const char *words[] = {"ab","bcb","bd","bc","cbcbc","cf","ce"};
    char* result[20000];
    int l = gen_chains_all(const_cast<char **>(words),7,result);
    EXPECT_EQ(l,29);
}
//有环简单测试，针对gen_chains_all是否正常报错
TEST(core,2) {
    const char *words[] = {"ab","bcb","bcbcb","bd","bc","cbcbc","cf","ce"};
    char* result[20000];
    int l = gen_chains_all(const_cast<char **>(words),7,result);
    EXPECT_TRUE(coreErrorDectect(result,l,NOT_EXIST_RING_PARA));
}

//无环简单测试针对gen_chain_word的各种简单组合情况
TEST(core, 3) {
    const char *words[] = {"ab", "bcb", "bd","cd","dbd"};
    //-w
    char * result[20000];
    int l = gen_chain_word(const_cast<char **>(words), 5, result, 0, 0, 0, false);
    EXPECT_TRUE(chainIsValid(l, result, 0, 0, 0));
    EXPECT_EQ(l, 4);
    //-w -h b
    char * result2[20000];
    int l2 = gen_chain_word(const_cast<char **>(words), 5, result2, 'b', 0, 0, false);
    EXPECT_TRUE(chainIsValid(l2, result2, 'b', 0, 0));
    EXPECT_EQ(l2, 3);
    //-w -t b
    char * result3[20000];
    int l3 = gen_chain_word(const_cast<char **>(words), 5, result3, 0, 'b', 0, false);
    EXPECT_TRUE(chainIsValid(l3, result3, 0, 'b', 0));
    EXPECT_EQ(l3, 2);
    //-w -t b -j a
    char * result4[20000];
    int l4 = gen_chain_word(const_cast<char **>(words), 5, result4, 0, 'b', 'a', false);
    EXPECT_TRUE(chainIsValid(l4, result4, 0, 'b', 'a'));
    EXPECT_EQ(l4, 0);
    ccout(result4,l4);
}

//无环简单测试针对gen_chain_word的各种复杂组合情况,有重复单词
TEST(core,4){
    const char *words[] = {"ab","ab","bcb", "bcb", "bd","cd","dbd"};
    //-w -h a -t c
    char * result[20000];
    int l = gen_chain_word(const_cast<char **>(words), 7, result, 'a', 'c', 0, false);
    EXPECT_TRUE(chainIsValid(l, result, 0, 0, 0));
    EXPECT_EQ(l, 0);

    //-w -h b -t d -j a
    char * result2[20000];
    int l2 = gen_chain_word(const_cast<char **>(words), 7, result2, 'b', 'd', 'a', false);
    EXPECT_TRUE(chainIsValid(l2, result2, 'b', 'd', 'a'));
    EXPECT_EQ(l2, 3);
}


//无环简单测试针对gen_chain_char的各种简单情况
TEST(core,5) {
    const char *words[] = {"ab","bcbcb", "bd","cd","dbd","cfffffffff","fffffffffff"};
    //-c
    char * result[20000];
    int l = gen_chain_char(const_cast<char **>(words), 7, result, 0, 0, 0, false);
    EXPECT_TRUE(chainIsValid(l, result, 0, 0, 0));
    EXPECT_EQ(l, 2);
    //-c -h b
    char * result2[20000];
    int l2 = gen_chain_char(const_cast<char **>(words), 7, result2, 'b', 0, 0, false);
    EXPECT_TRUE(chainIsValid(l2, result2, 0, 0, 0));
    EXPECT_EQ(l2, 3);
    //-c -t b
    char * result3[20000];
    int l3 = gen_chain_char(const_cast<char **>(words), 7, result3, 0, 'b', 0, false);
    EXPECT_TRUE(chainIsValid(l3, result3, 0, 'b', 0));
    EXPECT_EQ(l3, 2);
    //-c -j c
    char * result4[20000];
    int l4 = gen_chain_char(const_cast<char **>(words), 7, result4, 0, 0, 'c', false);
    EXPECT_TRUE(chainIsValid(l4, result4, 0, 0, 'c'));
    EXPECT_EQ(l4, 4);
}
//无环简单测试针对gen_chain_char的各种复杂组合情况，有重复单词,查看是否正确去除孤立自环边、孤立树边
TEST(core,6) {
    const char *words[] = {"ab","bcbcb", "bd","bd","cd","dbd","cfffffffff","fffffff",
                           "xkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkx"};
    //-c
    char * result[20000];
    int l = gen_chain_char(const_cast<char **>(words), 8, result, 0, 0, 0, false);
    EXPECT_TRUE(chainIsValid(l, result, 0, 0, 0));
    EXPECT_EQ(l, 2);
    //-c -t d -h b -j a
    char * result2[20000];
    int l2 = gen_chain_char(const_cast<char **>(words), 8, result2, 'b', 'd', 'a', false);
    EXPECT_TRUE(chainIsValid(l2, result2, 'b', 'd', 'a'));
    EXPECT_EQ(l2, 3);
}


//-------------------------以下是有环测试-----------------------------
//有环复杂测试 针对gen_word各种情况 -h，-t,-j
TEST(coreloop, 7) {
    const char *words[] = {"ababa", "adoctb", "boxa",
                           "cx", "aac", "cotb", "bard", "dddddddddddddddddddddddddddddd",
                           "cec", "ce", "ef", "fg", "ge", "cff", "fgg", "gee", "f", "ff",
                           "fff", "ffff"};
    char * result[20000];
    int l = gen_chain_word(const_cast<char **>(words), 20, result, 0, 0, 0, true);
    EXPECT_TRUE(chainIsValid(l, result, 0, 0, 0));
    EXPECT_EQ(l,15);
    char * result2[20000];
    int l2 = gen_chain_word(const_cast<char **>(words),20,result2,'c',0,0, true);
    EXPECT_TRUE(chainIsValid(l2,result2,'c',0,0));
    EXPECT_EQ(l, 15);
}

//有环复杂测试 针对gen_char各种情况
TEST(coreloop,8) {
    const char *words[] = {"Aa","af","afff","ffff","ff","fb","be",
                           "bd","ebe","ebebe","cf","bc","cd"};
    //-c -r
    char * result[20000];
    int l = gen_chain_char(const_cast<char **>(words), 13, result, 0, 0, 0, true);
    EXPECT_TRUE(chainIsValid(l, result, 0, 0, 0));
    EXPECT_EQ(l,8);
    //-c -r -h a -t f
    char * result2[20000];
    int l2 = gen_chain_char(const_cast<char **>(words), 13, result2, 'a', 'f', 0, true);
    EXPECT_TRUE(chainIsValid(l2, result2, 'a', 'f', 0));
    EXPECT_EQ(l2,7);
    //-c -r -h e -t e
    char * result3[20000];
    int l3 = gen_chain_char(const_cast<char **>(words), 13, result3, 'e', 'e', 0, true);
    ccout(result3,l3);
    EXPECT_TRUE(chainIsValid(l3, result3, 'e', 'e', 0));
    EXPECT_EQ(l3,2);
}

//------------------------------------------------以下针对core内部的2种异常进行测试
//针对core内部设计的3种error进行测试
//-h -t设置字母相同但是没有指定-r
TEST(coreerror,1){
    //-h -t设置字母相同但是没有指定-r
    const char *words[] = {"Aa","af","ac"};
    char * result[20000];
    int l = gen_chain_char(const_cast<char **>(words), 3, result, 'a', 'a', 0, false);
    EXPECT_TRUE(coreErrorDectect(result,l,HEAD_TAIL_LIMIT_SAME));

    char * result2[20000];
    int l2 = gen_chain_word(const_cast<char **>(words), 3, result2, 'a', 'a', 0, false);
    EXPECT_TRUE(coreErrorDectect(result2,l2,HEAD_TAIL_LIMIT_SAME));

}

//-h -j设置同一个字母矛盾
TEST(coreerror,2){
    const char *words[] = {"Aa","af","ac"};
    char * result[20000];
    int l = gen_chain_char(const_cast<char **>(words), 3, result, 'a', 'a', 'a', true);
    EXPECT_TRUE(coreErrorDectect(result,l,HEAD_LIMIT_CONTRADICTION));
    char * result2[20000];
    int l2 = gen_chain_word(const_cast<char **>(words), 3, result2, 'a', 'a', 'a', true);
    EXPECT_TRUE(coreErrorDectect(result2,l2,HEAD_LIMIT_CONTRADICTION));
}

//检查有环但是没有设置-r是否报错
TEST(coreerror,3) {
    const char *words[] = {"Aa","af","ac","aba","ca"};
    char * result[20000];
    int l = gen_chain_char(const_cast<char **>(words), 5, result, 0, 0, 0, false);
    EXPECT_TRUE(coreErrorDectect(result,l,NOT_EXIST_RING_PARA));

    char * result2[20000];
    int l2 = gen_chain_word(const_cast<char **>(words), 5, result2, 0, 0, 0, false);
    EXPECT_TRUE(coreErrorDectect(result2,l2,NOT_EXIST_RING_PARA));
}


int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}